﻿#include "C3fdCase.h"
#include <QDir>
#include <QDomDocument>
#include <QTextStream>
#include <QDebug>

namespace Common
{
	C3fdCase::C3fdCase(QString path)
		: m_CaseDir(path)
	{
		// 算例文件夹
		m_Names.insert("work_condition_dir", "WorkingConditions");
		m_Names.insert("mesh_dir", "mesh");
		m_Names.insert("solver_input_dir", "INPUT");
		m_Names.insert("solver_output_dir", "OUTPUT");

		// 网格
		m_Names.insert("mesh_control_file", "Imesh_control.dat");
		m_Names.insert("mesh_report_file", "Omesh_report.dat");
		m_Names.insert("3d_mesh_file", "Omesh_3d.dat");
		m_Names.insert("s2_mesh_file", "Omesh_s2.dat");
		m_Names.insert("b2b_mesh_hub_file", "Omesh_b2b_hub.dat");
		m_Names.insert("b2b_mesh_mid_file", "Omesh_b2b_mid.dat");
		m_Names.insert("b2b_mesh_tip_file", "Omesh_b2b_tip.dat");
		m_Names.insert("mesh_used_for_solver_file", "Omesh.msh");
		m_Names.insert("geom_info_of_blade_file", "Omesh_rowinf.dat");

		// 求解
		m_Names.insert("solver_control_file", "Solver_Control.dat");
		m_Names.insert("solver_tbmodel_file", "Solver_TBmodel.dat");
		m_Names.insert("solver_boundary_file", "Solver_Boundary.dat");
		m_Names.insert("solver_perfcurve_file", "Solver_PerfCurve.dat");
		m_Names.insert("solver_monitor_file", "monitor.dat");

		// 后处理

		m_ReportData = new C3fdReportData;
	}

	C3fdCase::~C3fdCase()
	{
		if (m_ReportData != nullptr)
		{
			delete m_ReportData;
			m_ReportData = nullptr;
		}
	}

	QString C3fdCase::getNameByKey(QString key) const
	{
		if (m_Names.contains(key))
		{
			return m_Names.value(key);
		}
		else
		{
			return "";
		}
	}

	QString C3fdCase::getWorkDir() const
	{
		return m_CaseDir;
	}

	void C3fdCase::addGeomTurboFile(GeomTurbo *geom)
	{
		geom->setRowNum(m_GeomTurboFiles.size() + 1);
		m_GeomTurboFiles.push_back(geom);
	}

	int C3fdCase::getNumOfGeomTurbo(QString name) const
	{
		for (auto geom : m_GeomTurboFiles)
		{
			if (geom->getFileName() == name)
			{
				return geom->getNumOfBlades();
			}
		}
		return 0;
	}

	void C3fdCase::clearGeomTurboFiles()
	{
		m_GeomTurboFiles.clear();
	}

	int C3fdCase::getNumOfBladeRow() const
	{
		return m_BladeRows.size();
	}

	QList<BladeRow *> C3fdCase::getBladeRows() const
	{
		return m_BladeRows;
	}

	BladeRow *C3fdCase::getBladeRowByRowNum(int num)
	{
		for (auto r : m_BladeRows)
		{
			if (r->getRowNum() == num)
			{
				return r;
			}
		}
		return nullptr;
	}

	void C3fdCase::addBladeRow(BladeRow *row)
	{
		m_BladeRows.push_back(row);
	}

	void C3fdCase::clearBladeRow()
	{
		m_BladeRows.clear();
	}

	QHash<QString, WorkCondition *> C3fdCase::getWorkConditions() const
	{
		return m_WorkConditions;
	}

	void C3fdCase::addWorkCondition(WorkCondition *wc)
	{
		if (wc->getOrder() == 0)
		{
			wc->setOrder(m_WorkConditions.size() + 1);
		}
		m_WorkConditions.insert(wc->getName(), wc);
	}

	bool C3fdCase::hasWorkCondition(QString name) const
	{
		return m_WorkConditions.keys().contains(name);
	}

	bool C3fdCase::removeWorkCondition(QString name)
	{
		return m_WorkConditions.remove(name) >= 1 ? true : false;
	}

	void C3fdCase::save()
	{
		QFile file(m_CaseDir + "Case.c3fd");
		if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
		{
			return;
		}

		QDomDocument doc;
		// 写入xml头部
		QDomProcessingInstruction instruction; // 添加处理命令
		instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
		doc.appendChild(instruction);

		// 添加根节点
		QDomElement root = doc.createElement("C3fdCase");
		doc.appendChild(root);

		// 几何节点
		QDomElement geoms = doc.createElement("Geometry");
		geoms.setAttribute("count", m_GeomTurboFiles.size());
		for (auto g : m_GeomTurboFiles)
		{
			QDomElement geom = doc.createElement("GeomTurbo");
			geom.setAttribute("file", g->getFileName());
			geom.setAttribute("blade", g->getNumOfBlades());
			geom.setAttribute("row", g->getRowNum());
			geom.setAttribute("parts", g->getParts().join(","));
			geoms.appendChild(geom);
		}
		root.appendChild(geoms);

		// 叶排
		QDomElement bladeRows = doc.createElement("BladeRows");
		bladeRows.setAttribute("count", m_BladeRows.size());
		for (auto r : m_BladeRows)
		{
			QDomElement bladeRow = doc.createElement("BladeRow");
			bladeRow.setAttribute("rowNum", r->getRowNum());
			bladeRow.setAttribute("bladeNum", r->getBladeNum());
			bladeRow.setAttribute("type", r->getType() == Common::BladeRowType::Stator ? 0 : 1);
			bladeRow.setAttribute("gap", r->getGap());
			bladeRow.setAttribute("rootFillet", r->getRootFillet());
			bladeRow.setAttribute("tipFillet", r->getTipFillet());
			bladeRow.setAttribute("unitRadio", r->getUnitRadio());
			bladeRow.setAttribute("geom", r->getGeomFileName());
			bladeRows.appendChild(bladeRow);
		}
		root.appendChild(bladeRows);

		// 工况
		QDomElement workConditions = doc.createElement("WorkConditions");
		workConditions.setAttribute("count", m_WorkConditions.size());
		int order = 0;
		for (auto k : m_WorkConditions.keys())
		{
			auto wc = m_WorkConditions.value(k);
			if (wc == nullptr)
			{
				continue;
			}
			QDomElement workCondition = doc.createElement("WorkCondition");
			workCondition.setAttribute("name", k);
			workCondition.setAttribute("order", wc->getOrder());
			workCondition.setAttribute("rotationSpeed", wc->getRotationSpeed());
			workCondition.setAttribute("intletTemp", wc->getIntletTemp());
			workCondition.setAttribute("intletPress", wc->getInletPress());
			workCondition.setAttribute("airFlowAngle", wc->getAirflowAngle());
			workCondition.setAttribute("outletPress", wc->getOutletPress());
			workCondition.setAttribute("startRotationSpeed", wc->getStartRotationSpeed());
			workCondition.setAttribute("interativeStep", wc->getInterativeStep());
			workConditions.appendChild(workCondition);
		}
		root.appendChild(workConditions);

		// 报告数据
		QDomElement report = doc.createElement("ReportData");

		QDomElement bladeRowDatas = doc.createElement("BladeRowDatas");
		for (auto data : m_ReportData->getMeshModel())
		{
			QDomElement bladeRowData = doc.createElement("BladeRowData");
			bladeRowData.setAttribute("name", data.name);
			bladeRowData.setAttribute("numOfBlade", data.numOfBlade);
			bladeRowData.setAttribute("gap", data.gap);
			bladeRowData.setAttribute("numOfMesh", data.numOfMesh);
			bladeRowDatas.appendChild(bladeRowData);
		}
		report.appendChild(bladeRowDatas);

		{
			auto data = m_ReportData->getBoundaryModel();
			QDomElement boundaryData = doc.createElement("BoundaryData");
			boundaryData.setAttribute("inletPressure", data.inletPressure);
			boundaryData.setAttribute("inletTemperature", data.inletTemperature);
			boundaryData.setAttribute("outletPressure", data.outletPressure);
			boundaryData.setAttribute("rotationSpeed", data.rotationSpeed);
			report.appendChild(boundaryData);
		}

		QDomElement performanceDataLists = doc.createElement("PerformanceDataLists");
		for (auto data : m_ReportData->getPerformanceDatas())
		{
			QDomElement performanceDataList = doc.createElement("PerformanceDataList");
			performanceDataList.setAttribute("name", data.name);
			performanceDataList.setAttribute("rotationSpeed", data.rotationSpeed);
			for (auto d : data.datas)
			{
				QDomElement performanceData = doc.createElement("PerformanceData");
				performanceData.setAttribute("inletFlow", d.inletFlow);
				performanceData.setAttribute("pressureRatio", d.pressureRatio);
				performanceData.setAttribute("efficiency", d.efficiency);
				performanceDataList.appendChild(performanceData);
			}
			performanceDataLists.appendChild(performanceDataList);
		}
		report.appendChild(performanceDataLists);

		QDomElement performanceImages = doc.createElement("PerformanceImages");
		for (auto data : m_ReportData->getPerformanceImages())
		{
			QDomElement performanceImage = doc.createElement("PerformanceImage");
			performanceImage.setAttribute("name", data.name);
			performanceImage.setAttribute("fileName", data.img);

			performanceImages.appendChild(performanceImage);
		}
		report.appendChild(performanceImages);

		QDomElement flowImages = doc.createElement("FlowImages");
		for (auto data : m_ReportData->getFlowImages())
		{
			QDomElement flowImage = doc.createElement("FlowImage");
			flowImage.setAttribute("name", data.name);
			QFileInfo fileInfo(data.img);
			flowImage.setAttribute("fileName", fileInfo.fileName());
			flowImages.appendChild(flowImage);
		}
		report.appendChild(flowImages);

		root.appendChild(report);

		// 输出到文件
		QTextStream out_stream(&file);
		doc.save(out_stream, 4); // 缩进4格
		file.close();
	}

	void C3fdCase::load()
	{
		QFile file(m_CaseDir + "Case.c3fd");
		if (!file.open(QFile::ReadOnly))
			return;

		QDomDocument doc;
		if (!doc.setContent(&file))
		{
			file.close();
			return;
		}
		file.close();

		QDomElement root = doc.documentElement(); // 返回根节点
		if (root.nodeName() != "C3fdCase")
		{
			return;
		}
		QDomNode node = root.firstChild(); // 获得第一个子节点
		while (!node.isNull())			   // 如果节点不空
		{
			if (node.isElement()) // 如果节点是元素
			{
				QDomElement element = node.toElement(); // 转换为元素，注意元素和节点是两个数据结构，其实差不多
				if (element.tagName() == "Geometry")
				{
					QDomNodeList childList = element.childNodes();
					int count = childList.size();
					for (int i = 0; i < count; ++i)
					{
						QDomNode n = childList.at(i);
						if (n.isElement())
						{
							this->addGeomTurboFile(parseGeomTurbo(n.toElement()));
						}
					}
				}
				else if (element.tagName() == "BladeRows")
				{
					QDomNodeList childList = element.childNodes();
					int count = childList.size();
					for (int i = 0; i < count; ++i)
					{
						QDomNode n = childList.at(i);
						if (n.isElement())
						{
							this->addBladeRow(parseBladeRow(n.toElement()));
						}
					}
				}
				else if (element.tagName() == "WorkConditions")
				{
					QDomNodeList childList = element.childNodes();
					int count = childList.size();
					QVector<WorkCondition *> tempVector(count);
					for (int i = 0; i < count; ++i)
					{
						QDomNode n = childList.at(i);
						if (n.isElement())
						{
							auto *wc = parseWorkCondition(n.toElement());
							if (wc->getOrder() <= 0)
							{
								wc->setOrder(i + 1);
							}
							if (wc->getOrder() <= count)
							{
								tempVector[wc->getOrder() - 1] = wc;
							}
						}
					}

					for (int i = 0; i < count; ++i)
					{
						this->addWorkCondition(tempVector[i]);
					}
				}
				else if (element.tagName() == "ReportData")
				{
					auto *reportData = this->getReportData();
					if (reportData == nullptr)
					{
						return;
					}
					QDomNodeList childList = element.childNodes();
					int count = childList.size();
					for (int i = 0; i < count; ++i)
					{
						QDomNode n = childList.at(i);
						if (!n.isElement())
						{
							continue;
						}
						if (n.nodeName() == "BladeRowDatas")
						{
							reportData->setMeshModel(parseMeshModel(n.toElement()));
						}
						else if (n.nodeName() == "BoundaryData")
						{
							reportData->setBoundaryModel(parseBoundaryModel(n.toElement()));
						}
						else if (n.nodeName() == "PerformanceDataLists")
						{
							reportData->setPerformanceDatas(parsePerformanceDatas(n.toElement()));
						}
						else if (n.nodeName() == "PerformanceImages")
						{
							reportData->setPerformanceImages(parsePerformanceImages(n.toElement()));
						}
						else if (n.nodeName() == "FlowImages")
						{
							reportData->setFlowImages(parseFlowImages(n.toElement()));
						}
					}
				}
			}
			node = node.nextSibling(); // 下一个兄弟节点,nextSiblingElement()是下一个兄弟元素，都差不多
		}
	}

	C3fdReportData *C3fdCase::getReportData()
	{
		return m_ReportData;
	}

	void C3fdCase::initCase()
	{
		if (m_CaseDir.isEmpty())
		{
			return;
		}

		QDir dir(m_CaseDir);
		if (!dir.exists())
		{
			return;
		}

		if (!dir.exists(m_Names.value("mesh_dir")))
		{
			dir.mkdir(m_Names.value("mesh_dir"));
		}

		if (!dir.exists(m_Names.value("work_condition_dir")))
		{
			dir.mkdir(m_Names.value("work_condition_dir"));
		}

		if (!dir.exists("temp"))
		{
			dir.mkdir("temp");
		}

		if (!dir.exists("data"))
		{
			dir.mkdir("data");
		}

		/*if (!dir.exists("GeomCache"))
		{
			dir.mkdir("GeomCache");
		}*/

		save();
	}

	GeomTurbo *C3fdCase::parseGeomTurbo(const QDomElement &dom)
	{
		auto *geom = new GeomTurbo;
		geom->setFileName(dom.attribute("file"));
		geom->setNumOfBlades(dom.attribute("blade").toInt());
		geom->setParts(dom.attribute("parts").split(","));
		geom->setRowNum(dom.attribute("row").toInt());
		return geom;
	}

	BladeRow *C3fdCase::parseBladeRow(const QDomElement &dom)
	{
		auto *row = new BladeRow;
		row->setGap(dom.attribute("gap").toDouble());
		row->setGeomFileName(dom.attribute("geom"));
		row->setRootFillet(dom.attribute("rootFillet").toDouble());
		row->setRowNum(dom.attribute("rowNum").toInt());
		row->setBladeNum(dom.attribute("bladeNum").toInt());
		row->setTipFillet(dom.attribute("tipFillet").toDouble());
		row->setType(dom.attribute("type").toInt() == 0 ? Common::BladeRowType::Stator : Common::BladeRowType::Rotor);
		row->setUnitRadio(dom.attribute("unitRadio").toDouble());
		return row;
	}

	WorkCondition *C3fdCase::parseWorkCondition(const QDomElement &dom)
	{
		auto *wc = new WorkCondition;
		auto oStr = dom.attribute("order");
		if (!oStr.isEmpty() && oStr != "")
		{
			wc->setOrder(oStr.toInt());
		}
		wc->setAirflowAngle(dom.attribute("airFlowAngle").toDouble());
		wc->setInletPress(dom.attribute("intletPress").toDouble());
		wc->setInterativeStep(dom.attribute("interativeStep").toInt());
		wc->setIntletTemp(dom.attribute("intletTemp").toDouble());
		wc->setName(dom.attribute("name"));
		wc->setOutletPress(dom.attribute("outletPress").toDouble());
		wc->setRotationSpeed(dom.attribute("rotationSpeed").toDouble());
		wc->setStartRotationSpeed(dom.attribute("startRotationSpeed").toInt());
		return wc;
	}

	QList<BladeRowData> C3fdCase::parseMeshModel(const QDomElement &dom)
	{
		QList<BladeRowData> datas;

		QDomNodeList childList = dom.childNodes();
		int count = childList.size();
		for (int i = 0; i < count; ++i)
		{
			QDomNode n = childList.at(i);
			if (!n.isElement())
			{
				continue;
			}
			auto childDom = n.toElement();
			BladeRowData data;
			data.name = childDom.attribute("name");
			data.gap = childDom.attribute("gap").toDouble();
			data.numOfBlade = childDom.attribute("numOfBlade").toInt();
			data.numOfMesh = childDom.attribute("numOfMesh").toInt();
			datas.push_back(data);
		}
		return datas;
	}

	BoundaryData C3fdCase::parseBoundaryModel(const QDomElement &dom)
	{
		BoundaryData data;

		data.inletPressure = dom.attribute("inletPressure").toDouble();
		data.inletTemperature = dom.attribute("inletTemperature").toDouble();
		data.outletPressure = dom.attribute("outletPressure").toDouble();
		data.rotationSpeed = dom.attribute("rotationSpeed").toDouble();

		return data;
	}

	QList<PerformanceDataList> C3fdCase::parsePerformanceDatas(const QDomElement &dom)
	{
		QList<PerformanceDataList> datas;

		QDomNodeList lChildList = dom.childNodes();
		int count = lChildList.size();
		for (int i = 0; i < count; ++i)
		{
			QDomNode n = lChildList.at(i);
			if (!n.isElement())
			{
				continue;
			}
			auto lChildNode = n.toElement();
			PerformanceDataList data;
			data.name = lChildNode.attribute("name");
			data.rotationSpeed = lChildNode.attribute("rotationSpeed").toDouble();

			auto dChildList = lChildNode.childNodes();
			int dcount = dChildList.size();
			for (int j = 0; j < dcount; ++j)
			{
				QDomNode dn = dChildList.at(i);
				if (!dn.isElement())
				{
					continue;
				}
				auto dChildNode = dn.toElement();
				PerformanceData d;
				d.inletFlow = dChildNode.attribute("inletFlow").toDouble();
				d.pressureRatio = dChildNode.attribute("pressureRatio").toDouble();
				d.efficiency = dChildNode.attribute("efficiency").toDouble();
				data.datas.push_back(d);
			}

			datas.push_back(data);
		}
		return datas;
	}

	QList<PerformanceImage> C3fdCase::parsePerformanceImages(const QDomElement &dom)
	{
		QList<PerformanceImage> datas;

		QDomNodeList pChildList = dom.childNodes();
		int count = pChildList.size();
		for (int i = 0; i < count; ++i)
		{
			QDomNode n = pChildList.at(i);
			if (!n.isElement())
			{
				continue;
			}
			auto pChildNode = n.toElement();
			PerformanceImage data;
			data.name = pChildNode.attribute("name");
			data.img = pChildNode.attribute("fileName");

			datas.push_back(data);
		}
		return datas;
	}

	QList<FlowImage> C3fdCase::parseFlowImages(const QDomElement &dom)
	{
		QList<FlowImage> datas;

		QDomNodeList childList = dom.childNodes();
		int count = childList.size();
		for (int i = 0; i < count; ++i)
		{
			QDomNode n = childList.at(i);
			if (!n.isElement())
			{
				continue;
			}
			auto childDom = n.toElement();
			FlowImage data;
			data.name = childDom.attribute("name");
			data.img = m_CaseDir + "temp" + QDir::separator() + childDom.attribute("fileName");
			datas.push_back(data);
		}
		return datas;
	}

	QList<GeomTurbo *> C3fdCase::getGeomTurboFiles() const
	{
		return m_GeomTurboFiles;
	}
}
